
#ifndef xrtc_endpoint_hpp
#define xrtc_endpoint_hpp

#include <stdio.h>
#include <glib.h>
#include <stdint.h>

#include "codecs.hpp"
#include "rtp/rtp_exten.hpp"
#include "rtp/rtcp/transport_feedback.hpp"
#include "xtlv_file.h"

#ifdef __cplusplus
extern "C" {
#endif
    
    enum rtc_stream_type{
        RTC_AUDIO = 0,
        RTC_VIDEO = 1,
        RTC_DATA = 2,
        RTC_STREAM_TYPE_MAX
    };
    
    enum rtc_data_type{
        RTC_RECV_CLEAR,
        RTC_DATA_TYPE_MAX
    };
    
    enum rtc_event_type{
        RTC_EVENT_SETUP = 0,
        RTC_EVENT_TIMER ,
        RTC_EVENT_MAX
    };

    typedef struct rtc_endpoint_st * rtc_endpoint_t;
    typedef void * rtc_endpoint_callback_link_t;
    typedef void (* rtc_endpoint_callback_on_destroy)(rtc_endpoint_t rtc, void * context);
    // return true to skip following callbacks
    typedef bool (* rtc_endpoint_callback_on_stream_data)(rtc_endpoint_t rtc, void * context, int stream_type, rtc_codec_id_t codec, rtc_codec_id_t fec_codec, int data_type, int is_rtcp, int is_rtx, unsigned char * buf, int len);
    typedef void (* rtc_endpoint_callback_on_event)(rtc_endpoint_t rtc, void * context, int event, void * event_arg1, int event_arg2);
    typedef struct rtc_endpoint_callbacks{
        void * context;
        rtc_endpoint_callback_on_destroy on_destroy;
        rtc_endpoint_callback_on_stream_data on_stream_data;
        rtc_endpoint_callback_on_event on_event;
    }rtc_endpoint_callbacks;

    rtc_endpoint_t rtc_endpoint_create(
            GMainContext * main_context,
            const std::string& rtc_id,
            const char * media_ip,
            int min_port,
            int max_port,
            bool is_dumping_rtp,
            bool is_dumping_rtcp,
            int max_video_bitrate,
            int min_video_kbps,
            bool is_translating_fec,
            bool disable_h264,
            bool enable_fec,
            bool compensate_rtcp,
            bool experiment_esmb,
            bool lost_0,
            bool enable_bwe,
            bool force_send_sr,
            bool send_nack,
            int nack_cache_size,
            bool drop_audio,
            bool drop_video
    );
    void rtc_endpoint_delete(rtc_endpoint_t rtc);
    void rtc_endpoint_get_drop(rtc_endpoint_t rtc, bool& drop_audio, bool& drop_video);
    void rtc_endpoint_set_drop(rtc_endpoint_t rtc, bool drop_audio, bool drop_video);
    rtc_endpoint_callback_link_t rtc_endpoint_register_callback(rtc_endpoint_t rtc, void * context, rtc_endpoint_callbacks * callbacks);
    void rtc_endpoint_unregister_callback(rtc_endpoint_t rtc, rtc_endpoint_callback_link_t link);
    const char * rtc_endpoint_get_id(rtc_endpoint_t rtc);
    gint64 rtc_endpoint_get_create_ts(rtc_endpoint_t rtc);
    //int rtc_endpoint_generate_offer(rtc_endpoint_t rtc);
    int rtc_endpoint_process_offer(rtc_endpoint_t rtc, const char * sdp, int sdp_len);
    int rtc_endpoint_generate_answer(rtc_endpoint_t rtc, int is_pranswer);
    int rtc_endpoint_generate_offer(rtc_endpoint_t rtc, std::list<std::string>& hints);
    int rtc_endpoint_process_answer(rtc_endpoint_t rtc, const char * sdp, int sdp_len, int is_pranswer);
    
    int rtc_endpoint_add_remote_candidate(rtc_endpoint_t rtc, int mlineindex, const char * mid, const char * candidate_str, int retryModifyCands);
    const char * rtc_endpoint_get_local_sdp(rtc_endpoint_t rtc, int *psdp_len);
    int rtc_endpoint_get_candidate_count(rtc_endpoint_t rtc, int stage);
    int rtc_endpoint_get_canidate(rtc_endpoint_t rtc, int stage, int *pmlineindex, const char ** pmid, const char ** pcandidate);
    int rtc_endpoint_get_mline_count(rtc_endpoint_t rtc);
    int rtc_endpoint_get_candidates(rtc_endpoint_t rtc, int stage, int mlineindex, const char ** pmid, int * pcandidate_count, char *** pcandidate);
    int rtc_endpoint_send_stream_data(rtc_endpoint_t rtc, int stream_type, rtc_codec_id_t codec, rtc_codec_id_t fec_codec, int is_rtcp, int is_rtx, unsigned char * buf, int len);
    int rtc_endpoint_get_stream_cryto_keys(rtc_endpoint_t rtc, int stream_type, unsigned char ** plocal, int * plocal_len, unsigned char ** premote, int *premote_len);
    
//    int rtc_endpoint_connect(rtc_endpoint_t rtc, rtc_endpoint_t sub_rtc);
    int rtc_endpoint_subscribe(rtc_endpoint_t rtc, rtc_endpoint_t pub_rtc, bool audio, bool video);
    int rtc_endpoint_unsubscribe(rtc_endpoint_t rtc, rtc_endpoint_t pub_rtc);
    rtc_endpoint_t rtc_endpoint_get_publisher(rtc_endpoint_t rtc);
    int rtc_endpoint_reset_pubrtc(rtc_endpoint_t rtc, rtc_endpoint_t pub_rtc);
    int rtc_endpoint_set_ntp(rtc_endpoint_t rtc, int stream_type, uint32_t ntp_msw, uint32_t ntp_lsw, uint32_t rtp_ts);
    int rtc_endpoint_set_CNSL(rtc_endpoint_t rtc, int stream_type, uint8_t l);
    int rtc_endpoint_enable_report(rtc_endpoint_t rtc, int enabled);
    int rtc_endpoint_req_pli(rtc_endpoint_t rtc);
    int rtc_endpoint_req_nack(rtc_endpoint_t rtc, int stream_type, uint16_t orig_pid, uint16_t orig_blp);

    // @deprecated
    void rtc_endpoint_update_remb(rtc_endpoint_t rtc, uint32_t ssrc, uint32_t remb_bitrate);
    /** send remb only if ssrc is for local video stream
     * @param rtc
     * @param ssrc
     */
    void rtc_endpoint_send_immediate_remb_for_video_stream(rtc_endpoint_t rtc);

    void rtc_endpoint_set_user_data(rtc_endpoint_t rtc, const char* name, const void * userdata, int size);
    const void * rtc_endpoint_get_user_data(rtc_endpoint_t rtc, const char* name);
    int rtc_endpoint_check_live(rtc_endpoint_t rtc, int64_t now);
    const char* rtc_endpoint_get_filename(rtc_endpoint_t rtc);
    int rtc_endpoint_set_filename(rtc_endpoint_t rtc, const char * filename, int filename_length);
    int rtc_endpoint_is_setup(rtc_endpoint_t rtc);
    
    int rtc_endpoint_write_tlv_header(rtc_endpoint_t rtc, tlv_file_t tlv);
    int rtc_endpoint_write_tlv_tail(tlv_file_t tlv);
    int rtc_endpoint_write_tlv_rtp_rtcp(tlv_file_t tlv, int is_rtcp, unsigned char * buf, int buf_len);
    int rtc_endpoint_is_offer_role(rtc_endpoint_t rtc);

    int rtc_endpoint_start_record(rtc_endpoint_t rtc, const char* path_name, const char* context_data);
    int rtc_endpoint_stop_record(rtc_endpoint_t rtc, const char* path_name);

    uint8_t* rtc_endpoint_get_h264_sps_pps(rtc_endpoint_t rtc);
    size_t rtc_endpoint_get_h264_sps_pps_len(rtc_endpoint_t rtc);
    void rtc_endpoint_update_report(rtc_endpoint_t rtc, uint64_t recv_ts, uint32_t ssrc, uint32_t hseq, uint32_t rtt, uint32_t jitter, uint8_t lost_frac, uint32_t lost_cum);
    void rtc_endpoint_update_transport_feedback(rtc_endpoint_t rtc, const TransportFeedback& fb);
    rtc_codecs_t* rtc_endpoint_codecs(rtc_endpoint_t rtc);
    RtpExtensionMap* rtc_endpoint_audio_extension_map(rtc_endpoint_t rtc);
    uint32_t rtc_endpoint_get_remote_audio_ssrc(rtc_endpoint_t rtc);
    void rtc_endpoint_override_remote_audio_ssrc(rtc_endpoint_t rtc, uint32_t ssrc);
    void rtc_endpoint_reset_bytes(rtc_endpoint_t rtc, uint64_t* send, uint64_t* recv);
    void rtc_endpoint_reset_packets(rtc_endpoint_t rtc, uint64_t* send, uint64_t* recv);
    void rtc_endpoint_get_bytes(rtc_endpoint_t rtc,
                                uint64_t *audio_send_rtp, uint64_t *audio_send_rtcp, uint64_t* audio_send_dtls,
                                uint64_t *audio_recv_rtp, uint64_t *audio_recv_rtcp, uint64_t* audio_recv_dtls, uint64_t *audio_recv_unknown,
                                uint64_t *video_send_rtp, uint64_t *video_send_rtcp, uint64_t* video_send_dtls,
                                uint64_t *video_recv_rtp, uint64_t *video_recv_rtcp, uint64_t* video_recv_dtls, uint64_t *video_recv_unknown);

    int rtc_endpoint_remote_pub(rtc_endpoint_t pub_rtc, const std::string& sub_rtc_id, bool audio, bool video, const std::string& link_addr,
            int requireCheckRR, std::vector<uint32_t> sub_peer_audio_ssrcs, std::vector<uint32_t> sub_peer_video_ssrcs);
    int rtc_endpoint_remote_upub(rtc_endpoint_t pub_rtc, const std::string& sub_rtc_id);

    /** we can do better if we share stream info with others
     *
     * **/
    void rtc_endpoint_get_relay_audio_ssrc_list(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);
    void rtc_endpoint_get_relay_video_ssrc_list(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);
    void rtc_endpoint_get_local_audio_ssrc(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);
    void rtc_endpoint_get_local_video_ssrc(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);
    void rtc_endpoint_get_remote_audio_ssrc_list(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);
    void rtc_endpoint_get_remote_video_ssrc_list(rtc_endpoint_t rtc, std::vector<uint32_t> &ssrcs);

    void dump_rtcp(rtc_endpoint_t rtc, const char * prefix, void* buf_, int len);
#ifdef __cplusplus
}
#endif

#endif /* xrtc_endpoint_hpp */
